/*****************************************************************************/
/*!	\file		PIS10CreateServerClient.c
 *	\brief		C Source code file for the YX-PIS Example
 *	\par		Dalian Yunxing Tech Co., Ltd.
 *
 *				Dalian, China
 *				Phone   : +86 (411) 8825 4852
 *				Email   : yx@yunxing.tech
 */
/*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "PIS10CreateServerClient.h"
#include "PIS10Callbacks.h"
#include "IEC61850API.h"

static IEC61850 s_iec61850 = NULL;

IEC61850_ErrorCode CreateServer(unsigned long int options)
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850_Parameters params = { 0 };	// always set IEC61850_Parameters to 0 value

	if (IsMyServerClientNULL() == 1) {	// check whether the IEC61850 object is not created yet
		params.clientServerFlag = IEC61850_SERVER;	// this is an IEC61850 server
		params.Ed1_Ed2_Flag = IEC61850_Edition2;	// set YX-PIS to use Edition2
		params.options = options;	// set IEC61850_OptionFlag
		params.fnReadCallback = (IEC61850_ReadCallback)ReadCallbackHandler;
		params.fnWriteCallback = (IEC61850_WriteCallback)WriteCallbackHandler;
		params.fnUpdateCallback = (IEC61850_UpdateCallback)UpdateCallbackHandler;
		params.fnSelectCallback = (IEC61850_ControlSelectCallback)SelectCallbackHandler;
		params.fnOprTestCallback = (IEC61850_ControlOperativeTestCallback)OperativeTestCallbackHandler;
		params.fnOperateCallback = (IEC61850_ControlOperateCallback)OperateCallbackHandler;
		params.fnCancelCallback = (IEC61850_ControlCancelCallback)CancelCallbackHandler;
		params.fnQuestionableCallback = (IEC61850_DataPointQuestionableCallback)QuestionableCallbackHandler;
		params.fnFileCallback = (IEC61850_FileCallback)FileCallbackHandler;
		params.fnSettingGroupCallback = (IEC61850_SettingGroupCallback)SettingGroupCallback;

		params.dataMapMode = IEC61850_MAP_MODE_DAID;

		s_iec61850 = IEC61850_Create(&params, &result);
		if (s_iec61850 == NULL) {
			printf("   Server Failed to create: %s (%i)\n", IEC61850_ErrorString(result), result);
			if ((result == IEC61850_ERROR_GOOSE_SERVICE_FAILED) || (result == IEC61850_ERROR_GOOSE_INIT_FAILED)) {
				printf("NOTE: GOOSE Protocol is not supported by WIFI networks, please make sure you are using a Wired Ethernet Adapter\n Make sure your user has permission to run raw socket capture (pcap)\n\n");
			}
		}
	} else {
		result = IEC61850_ERROR_INVALID_STATE;
	}

	return result;
}

IEC61850_ErrorCode CreateClient()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850_Parameters params = { 0 };	// always set IEC61850_Parameters to 0 value
	unsigned long int options = IEC61850_OPTION_NONE;

	if (IsMyServerClientNULL() == 1) {	// check whether the IEC61850 object is not created yet
		params.clientServerFlag = IEC61850_CLIENT;	// this is an IEC61850 client
		params.Ed1_Ed2_Flag = IEC61850_Edition2;	// set YX-PIS to use Edition2
		params.options = options;	// set IEC61850_OptionFlag
		params.fnUpdateCallback = (IEC61850_UpdateCallback)UpdateCallbackHandler;
		params.fnErrorCallback = (IEC61850_ErrorCallback)ErrorCallbackHandler;
		params.fnQuestionableCallback = (IEC61850_DataPointQuestionableCallback)QuestionableCallbackHandler;
		params.fnCmdTermCallback = (IEC61850_ControlCommandTerminationCallback)CommandTerminationCallback;
		// params.fnConnectionStatusCallback = (IEC61850_ConnectionStatusCallback)ConnectionStatusCallbackHandler;

		params.dataMapMode = IEC61850_MAP_MODE_DAID;

		s_iec61850 = IEC61850_Create(&params, &result);
		if (s_iec61850 == NULL) {
			printf("   Client Failed to create: %s (%i)\n", IEC61850_ErrorString(result), result);
			if ((result == IEC61850_ERROR_GOOSE_SERVICE_FAILED) || (result == IEC61850_ERROR_GOOSE_INIT_FAILED)) {
				printf("NOTE: GOOSE Protocol is not supported by WIFI networks, please make sure you are using a Wired Ethernet Adapter\n Make sure your user has permission to run raw socket capture (pcap)\n\n");
			}
		}
	} else {
		result = IEC61850_ERROR_INVALID_STATE;
	}

	return result;
}

IEC61850_ErrorCode LoadSCLFile(char* fileName)
{
	IEC61850_ErrorCode result = S_OK;
	result = IEC61850_LoadSCLFile(s_iec61850, fileName); // Load in IED configuration SCL file

	if (result != S_OK) {
		printf("   Loading SCL file (%s) has failed: %s (%i)\n", fileName, IEC61850_ErrorString(result), result);

		if ((result == IEC61850_ERROR_INVALID_IP_ADDRESS) || (result == IEC61850_ERROR_GOOSE_SERVICE_FAILED) || (result == IEC61850_ERROR_GOOSE_INIT_FAILED)) {
			printf("\nPlease check that you have set your IP Address in the CID file %s \n", fileName);

			printf("<Address>\n   <P type = \"OSI-AP-Title\">1, 1, 9999, 1</P>\n   <P type = \"OSI-AE-Qualifier\">12</P>\n   <P type = \"OSI-PSEL\">00000001</P>\n   <P type = \"OSI-SSEL\">0001</P>\n   <P type = \"OSI-TSEL\">0001</P>\n");
			printf("   <P type = \"IP\">192.168.1.100</P>   <!--Put the IP Address Here-->\n   <P type = \"IP-SUBNET\">255.255.255.0</P>\n   <P type = \"IP-GATEWAY\">192.168.1.1</P>\n</Address>\n");

			printf("NOTE: GOOSE Protocol is not supported by WIFI networks, please make sure you are using a Wired Ethernet Adapter\n Make sure your user has permission to run raw socket capture (pcap)\n\n");
		}
	}

	return result;
}

IEC61850_ErrorCode StartMyServerClient()
{
	IEC61850_ErrorCode result = S_OK;
	result = IEC61850_Start(s_iec61850);

	if (result != S_OK) {
		printf("   Can't start server: %s (%i)\n", IEC61850_ErrorString(result), result);

		if ((result == IEC61850_ERROR_GOOSE_SERVICE_FAILED) || (result == IEC61850_ERROR_GOOSE_INIT_FAILED)) {
			printf("\nPlease check that you have set the correct IP Address in the CID file\n");
			printf("NOTE: GOOSE Protocol is not supported by WIFI networks,\n");
			printf("      please make sure you are using a Wired Ethernet Adapter,\n");
			printf("      and your user has permission to run raw socket capture (pcap).\n");
			printf("      If the instance is a GOOSE Subscriber, check whether the GOOSE feature was enabled.\n\n");
		}
	}

	return result;
}

IEC61850_ErrorCode StopMyServerClient()
{
	IEC61850_ErrorCode result = S_OK;
	result = IEC61850_Stop(s_iec61850);
	if ((result != S_OK) && (result != IEC61850_ERROR_INVALID_STATE)) {
		printf("   Can't stop server: %s (%i)\n", IEC61850_ErrorString(result), result);
	}

	return result;
}

int IsMyServerClientNULL()
{
	int isNULL = 1;

	if (s_iec61850) {
		isNULL = 0;
	}

	return isNULL;
}

IEC61850 GetMyServerClient()
{
	return s_iec61850;
}

void SetMyServerClient(IEC61850 iec61850)
{
	s_iec61850 = iec61850;
}

IEC61850_ErrorCode FreeMyServerClient()
{
	IEC61850_ErrorCode result = S_OK;

	result = IEC61850_Free(s_iec61850);

	if (result == S_OK) {
		s_iec61850 = NULL;
	} else {
		printf("   Free IEC61850 Object has failed: %s (%i)\n", IEC61850_ErrorString(result), result);
	}

	return result;
}

IEC61850_ErrorCode SetUserData(void* data)
{
	IEC61850_ErrorCode result = S_OK;

	result = IEC61850_SetUserData(s_iec61850, data);

	return result;
}

IEC61850_ErrorCode SetControlsOrCat()
{
	IEC61850_ErrorCode result = S_OK;
	eOriginatorCat orCat = ORCAT_BAY_CONTROL;	// set orCat as bay-control
	char *orIdent = NULL;	// leave the orIdent as default - the IP Address of client

	// call the API to set the originator for all controls
	result = IEC61850_SetOriginator(s_iec61850, NULL, orCat, orIdent, 0);

	return result;
}
